Skip to content
This repository was archived by the owner on Feb 20, 2023. It is now read-only.

Commit 7b895ab

Browse files
sarah541mergify[bot]
authored andcommitted
For #24455 - Migrate NoCollectionsMessageViewHolder to Compose
1 parent 7f3aa6a commit 7b895ab

File tree

9 files changed

+221
-230
lines changed

9 files changed

+221
-230
lines changed

app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import androidx.test.uiautomator.Until
3333
import androidx.test.uiautomator.Until.findObject
3434
import mozilla.components.browser.state.state.searchEngines
3535
import org.hamcrest.CoreMatchers.allOf
36-
import org.hamcrest.CoreMatchers.containsString
3736
import org.hamcrest.CoreMatchers.instanceOf
3837
import org.hamcrest.CoreMatchers.not
3938
import org.hamcrest.Matchers
@@ -141,7 +140,11 @@ class HomeScreenRobot {
141140
fun verifyRecentBookmarksSectionIsDisplayed() = assertRecentBookmarksSectionIsDisplayed()
142141
fun verifyRecentBookmarksSectionIsNotDisplayed() = assertRecentBookmarksSectionIsNotDisplayed()
143142

144-
fun verifyRecentlyVisitedSearchGroupDisplayed(shouldBeDisplayed: Boolean, searchTerm: String, groupSize: Int) {
143+
fun verifyRecentlyVisitedSearchGroupDisplayed(
144+
shouldBeDisplayed: Boolean,
145+
searchTerm: String,
146+
groupSize: Int
147+
) {
145148
// checks if the search group exists in the Recently visited section
146149
if (shouldBeDisplayed) {
147150
recentlyVisitedList.waitForExists(waitingTime)
@@ -162,7 +165,11 @@ class HomeScreenRobot {
162165
}
163166
}
164167

165-
fun verifyCurrentSearchGroupIsDisplayed(shouldBeDisplayed: Boolean, searchTerm: String, groupSize: Int = 0) {
168+
fun verifyCurrentSearchGroupIsDisplayed(
169+
shouldBeDisplayed: Boolean,
170+
searchTerm: String,
171+
groupSize: Int = 0
172+
) {
166173
// checks search group in the Jump back in section
167174
if (shouldBeDisplayed) {
168175
assertTrue(
@@ -392,7 +399,10 @@ class HomeScreenRobot {
392399
return TabDrawerRobot.Transition()
393400
}
394401

395-
fun expandCollection(title: String, interact: CollectionRobot.() -> Unit): CollectionRobot.Transition {
402+
fun expandCollection(
403+
title: String,
404+
interact: CollectionRobot.() -> Unit
405+
): CollectionRobot.Transition {
396406
// Depending on the screen dimensions collections might report as visible on screen
397407
// but actually have the bottom toolbar above so interactions with collections might fail.
398408
// As a quick solution we'll try scrolling to the element below collection on the homescreen
@@ -405,8 +415,12 @@ class HomeScreenRobot {
405415
return CollectionRobot.Transition()
406416
}
407417

408-
fun openRecentlyVisitedSearchGroupHistoryList(title: String, interact: HistoryRobot.() -> Unit): HistoryRobot.Transition {
409-
val searchGroup = recentlyVisitedList.getChildByText(UiSelector().text(title), title, true)
418+
fun openRecentlyVisitedSearchGroupHistoryList(
419+
title: String,
420+
interact: HistoryRobot.() -> Unit
421+
): HistoryRobot.Transition {
422+
val searchGroup =
423+
recentlyVisitedList.getChildByText(UiSelector().text(title), title, true)
410424
searchGroup.waitForExists(waitingTimeShort)
411425
searchGroup.click()
412426

@@ -438,7 +452,8 @@ private fun assertKeyboardVisibility(isExpectedToBeVisible: Boolean) =
438452
.contains("mInputShown=true")
439453
)
440454

441-
private fun navigationToolbar() = mDevice.findObject(UiSelector().resourceId("$packageName:id/toolbar"))
455+
private fun navigationToolbar() =
456+
mDevice.findObject(UiSelector().resourceId("$packageName:id/toolbar"))
442457

443458
private fun assertNavigationToolbar() = assertTrue(navigationToolbar().waitForExists(waitingTime))
444459

@@ -447,7 +462,8 @@ private fun assertFocusedNavigationToolbar() =
447462
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
448463

449464
private fun assertHomeScreen() {
450-
mDevice.findObject(UiSelector().resourceId("$packageName:id/homeLayout")).waitForExists(waitingTime)
465+
mDevice.findObject(UiSelector().resourceId("$packageName:id/homeLayout"))
466+
.waitForExists(waitingTime)
451467
onView(ViewMatchers.withResourceName("homeLayout"))
452468
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
453469
}
@@ -471,18 +487,23 @@ private fun assertTabButton() =
471487
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
472488

473489
private fun assertCollectionsHeader() =
474-
onView(allOf(withText("Collections")))
475-
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
490+
assertTrue(
491+
mDevice.findObject(
492+
UiSelector().textContains(
493+
"Collections"
494+
)
495+
).waitForExists(waitingTime)
496+
)
476497

477498
private fun assertNoCollectionsText() =
478-
onView(
479-
withText(
480-
containsString(
499+
assertTrue(
500+
mDevice.findObject(
501+
UiSelector().textContains(
481502
"Collect the things that matter to you.\n" +
482503
"Group together similar searches, sites, and tabs for quick access later."
483504
)
484-
)
485-
).check(matches(isDisplayed()))
505+
).waitForExists(waitingTime)
506+
)
486507

487508
private fun assertHomeComponent() =
488509
onView(ViewMatchers.withResourceName("sessionControlRecyclerView"))
@@ -521,6 +542,7 @@ private fun assertStartSyncHeader() {
521542
onView(allOf(withText(R.string.onboarding_account_sign_in_header_1)))
522543
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
523544
}
545+
524546
private fun assertAccountsSignInButton() =
525547
onView(ViewMatchers.withResourceName("fxa_sign_in_button"))
526548
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
@@ -530,6 +552,7 @@ private fun assertChooseThemeHeader() {
530552
onView(withText("Choose your theme"))
531553
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
532554
}
555+
533556
private fun assertChooseThemeText() {
534557
scrollToElementByText("Choose your theme")
535558
onView(allOf(withText("Save some battery and your eyesight with dark mode.")))
@@ -559,6 +582,7 @@ private fun assertDarkThemeDescription() {
559582
onView(allOf(withText("Dark theme")))
560583
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
561584
}
585+
562586
private fun assertAutomaticThemeToggle() {
563587
scrollToElementByText("Choose your theme")
564588
onView(withId(R.id.theme_automatic_radio_button))
@@ -686,9 +710,11 @@ private fun assertTopSiteContextMenuItems() {
686710
)
687711
}
688712

689-
private fun assertJumpBackInSectionIsDisplayed() = assertTrue(jumpBackInSection().waitForExists(waitingTime))
713+
private fun assertJumpBackInSectionIsDisplayed() =
714+
assertTrue(jumpBackInSection().waitForExists(waitingTime))
690715

691-
private fun assertJumpBackInSectionIsNotDisplayed() = assertFalse(jumpBackInSection().waitForExists(waitingTimeShort))
716+
private fun assertJumpBackInSectionIsNotDisplayed() =
717+
assertFalse(jumpBackInSection().waitForExists(waitingTimeShort))
692718

693719
private fun assertRecentBookmarksSectionIsDisplayed() =
694720
assertTrue(recentBookmarksSection().waitForExists(waitingTime))
@@ -698,7 +724,8 @@ private fun assertRecentBookmarksSectionIsNotDisplayed() =
698724

699725
private fun privateBrowsingButton() = onView(withId(R.id.privateBrowsingButton))
700726

701-
private fun saveTabsToCollectionButton() = onView(withId(R.id.add_tabs_to_collections_button))
727+
private fun saveTabsToCollectionButton() =
728+
mDevice.findObject(UiSelector().textContains(getStringResource(R.string.tabs_menu_save_to_collection1)))
702729

703730
private fun tabsCounter() = onView(withId(R.id.tab_button))
704731

@@ -709,7 +736,8 @@ private fun recentBookmarksSection() =
709736
mDevice.findObject(UiSelector().textContains(getStringResource(R.string.recent_bookmarks_title)))
710737

711738
private fun startBrowsingButton(): UiObject {
712-
val startBrowsingButton = mDevice.findObject(UiSelector().resourceId("$packageName:id/finish_button"))
739+
val startBrowsingButton =
740+
mDevice.findObject(UiSelector().resourceId("$packageName:id/finish_button"))
713741
homeScreenList()
714742
.scrollIntoView(startBrowsingButton)
715743
homeScreenList()
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
package org.mozilla.fenix.compose
6+
7+
import androidx.compose.foundation.background
8+
import androidx.compose.foundation.layout.Box
9+
import androidx.compose.foundation.layout.Column
10+
import androidx.compose.foundation.layout.height
11+
import androidx.compose.foundation.layout.Row
12+
import androidx.compose.foundation.layout.fillMaxWidth
13+
import androidx.compose.foundation.layout.padding
14+
import androidx.compose.foundation.layout.size
15+
import androidx.compose.foundation.layout.Spacer
16+
import androidx.compose.material.Icon
17+
import androidx.compose.material.IconButton
18+
import androidx.compose.runtime.Composable
19+
import androidx.compose.ui.Modifier
20+
import androidx.compose.ui.res.painterResource
21+
import androidx.compose.ui.res.stringResource
22+
import androidx.compose.ui.semantics.semantics
23+
import androidx.compose.ui.tooling.preview.Preview
24+
import androidx.compose.ui.unit.dp
25+
import androidx.compose.ui.unit.sp
26+
import org.mozilla.fenix.R
27+
import org.mozilla.fenix.compose.button.PrimaryButton
28+
import org.mozilla.fenix.compose.ext.dashedBorder
29+
import org.mozilla.fenix.theme.FirefoxTheme
30+
import org.mozilla.fenix.theme.Theme
31+
32+
/**
33+
* [CollectionsPlaceholder] for displaying a message detailing the collections feature and
34+
* allowing users to easily start creating their collection.
35+
*
36+
* @param showAddToCollectionButton Whether or not the "Add to Collection" button should be shown.
37+
* @param onAddTabsToCollectionButtonClick Invoked when the user clicks on the "Add Tabs to Collection" button.
38+
* @param onRemovePlaceholderClick Invoked when the user clicks on the close button to remove the Collections
39+
* placeholder.
40+
*/
41+
@Composable
42+
fun CollectionsPlaceholder(
43+
showAddToCollectionButton: Boolean,
44+
onAddTabsToCollectionButtonClick: () -> Unit,
45+
onRemovePlaceholderClick: () -> Unit,
46+
) {
47+
Box(
48+
modifier = Modifier
49+
.semantics(mergeDescendants = true) {}
50+
.dashedBorder(
51+
color = FirefoxTheme.colors.borderPrimary,
52+
cornerRadius = 8.dp,
53+
dashHeight = 2.dp,
54+
dashWidth = 4.dp
55+
)
56+
) {
57+
Column(
58+
Modifier
59+
.padding(16.dp)
60+
.fillMaxWidth()
61+
) {
62+
Row(
63+
modifier = Modifier.fillMaxWidth(),
64+
) {
65+
SectionHeader(
66+
text = stringResource(R.string.collections_header),
67+
modifier = Modifier.weight(1f)
68+
)
69+
70+
IconButton(
71+
onClick = onRemovePlaceholderClick,
72+
modifier = Modifier.size(20.dp),
73+
) {
74+
Icon(
75+
painter = painterResource(R.drawable.ic_close),
76+
contentDescription = stringResource(
77+
R.string.remove_home_collection_placeholder_content_description
78+
),
79+
tint = FirefoxTheme.colors.iconPrimary
80+
)
81+
}
82+
}
83+
84+
Spacer(modifier = Modifier.height(4.dp))
85+
86+
SecondaryText(
87+
text = stringResource(R.string.no_collections_description2),
88+
modifier = Modifier.fillMaxWidth(),
89+
fontSize = 14.sp
90+
)
91+
92+
if (showAddToCollectionButton) {
93+
Spacer(modifier = Modifier.height(12.dp))
94+
95+
PrimaryButton(
96+
text = stringResource(R.string.tabs_menu_save_to_collection1),
97+
icon = painterResource(R.drawable.ic_tab_collection),
98+
onClick = onAddTabsToCollectionButtonClick
99+
)
100+
}
101+
}
102+
}
103+
}
104+
105+
@Composable
106+
@Preview
107+
private fun CollectionsPlaceholderPreview() {
108+
FirefoxTheme(theme = Theme.getTheme(isPrivate = false)) {
109+
Box(Modifier.background(FirefoxTheme.colors.layer1)) {
110+
CollectionsPlaceholder(
111+
showAddToCollectionButton = true,
112+
onAddTabsToCollectionButtonClick = {},
113+
onRemovePlaceholderClick = {}
114+
)
115+
}
116+
}
117+
}

app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
2828
import androidx.constraintlayout.widget.ConstraintSet.TOP
2929
import androidx.coordinatorlayout.widget.CoordinatorLayout
3030
import androidx.core.content.ContextCompat
31-
import androidx.core.view.isVisible
3231
import androidx.core.view.updateLayoutParams
3332
import androidx.fragment.app.Fragment
3433
import androidx.fragment.app.activityViewModels
@@ -37,7 +36,6 @@ import androidx.lifecycle.lifecycleScope
3736
import androidx.navigation.fragment.findNavController
3837
import androidx.navigation.fragment.navArgs
3938
import com.google.android.material.appbar.AppBarLayout
40-
import com.google.android.material.button.MaterialButton
4139
import com.google.android.material.snackbar.Snackbar
4240
import kotlinx.coroutines.Dispatchers.IO
4341
import kotlinx.coroutines.Dispatchers.Main
@@ -1069,9 +1067,6 @@ class HomeFragment : Fragment() {
10691067
}
10701068

10711069
binding.tabButton.setCountWithAnimation(tabCount)
1072-
// The add_tabs_to_collections_button is added at runtime. We need to search for it in the same way.
1073-
sessionControlView?.view?.findViewById<MaterialButton>(R.id.add_tabs_to_collections_button)
1074-
?.isVisible = tabCount > 0
10751070
}
10761071

10771072
private fun displayWallpaperIfEnabled() {

app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ sealed class AdapterItem(@LayoutRes val viewType: Int) {
171171

172172
object PocketStoriesItem : AdapterItem(PocketStoriesViewHolder.LAYOUT_ID)
173173
object PocketCategoriesItem : AdapterItem(PocketCategoriesViewHolder.LAYOUT_ID)
174-
object PocketRecommendationsFooterItem : AdapterItem(PocketRecommendationsHeaderViewHolder.LAYOUT_ID)
174+
object PocketRecommendationsFooterItem :
175+
AdapterItem(PocketRecommendationsHeaderViewHolder.LAYOUT_ID)
175176

176177
object BottomSpacer : AdapterItem(BottomSpacerViewHolder.LAYOUT_ID)
177178

@@ -272,19 +273,21 @@ class SessionControlAdapter(
272273
composeView = ComposeView(parent.context),
273274
viewLifecycleOwner = viewLifecycleOwner
274275
)
276+
NoCollectionsMessageViewHolder.LAYOUT_ID -> return NoCollectionsMessageViewHolder(
277+
composeView = ComposeView(parent.context),
278+
viewLifecycleOwner = viewLifecycleOwner,
279+
interactor = interactor
280+
)
275281
}
276282

277283
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
278284
return when (viewType) {
279285
TopPlaceholderViewHolder.LAYOUT_ID -> TopPlaceholderViewHolder(view)
280-
TopSitePagerViewHolder.LAYOUT_ID -> TopSitePagerViewHolder(view, viewLifecycleOwner, interactor)
281-
NoCollectionsMessageViewHolder.LAYOUT_ID ->
282-
NoCollectionsMessageViewHolder(
283-
view,
284-
viewLifecycleOwner,
285-
components.core.store,
286-
interactor
287-
)
286+
TopSitePagerViewHolder.LAYOUT_ID -> TopSitePagerViewHolder(
287+
view = view,
288+
viewLifecycleOwner = viewLifecycleOwner,
289+
interactor = interactor
290+
)
288291
CollectionViewHolder.LAYOUT_ID -> CollectionViewHolder(view, interactor)
289292
TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(
290293
view as WidgetSiteItemView,
@@ -315,6 +318,7 @@ class SessionControlAdapter(
315318
when (holder) {
316319
is CollectionHeaderViewHolder,
317320
is CustomizeHomeButtonViewHolder,
321+
is NoCollectionsMessageViewHolder,
318322
is RecentlyVisitedViewHolder,
319323
is RecentVisitsHeaderViewHolder,
320324
is RecentBookmarksViewHolder,

0 commit comments

Comments
 (0)